﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using iSteam.Sdk.Data;

namespace iSteam.Sdk.SmartObjects
{
    public class iUser : iBase
    {
        private User _user;
        private List<Group> _groups;
        private List<Friend> _friends;

        private List<iUser> _iUsers;
        private List<iGroup> _iGroups;

        private LoadType _loadType;


        public delegate void MessageReceivedEventHandler(object sender, OnMessageReceivedEventArgs e);
        public event MessageReceivedEventHandler MessageReceivedEvent;
        public void OnMessageReceivedEvent(OnMessageReceivedEventArgs e)
        {
            MessageReceivedEventHandler handler = MessageReceivedEvent;
            if (handler != null) handler(this, e);
        }

        public delegate void UpdatedEventHandler(object sender, OnUpdatedEventArgs e);
        public event UpdatedEventHandler UpdatedEvent;
        public void OnUpdatedEvent(OnUpdatedEventArgs e)
        {
            UpdatedEventHandler handler = UpdatedEvent;
            if (handler != null) handler(this, e);
        }

        public iUser(SteamToken token, bool autoUpdate = false, LoadType loadType = LoadType.OnRequest) : base(token)
        {
            Ini(loadType);
            if (autoUpdate)
            {
                token.MessageReceived += _notification_MessageReceived;
            }
        }
        public iUser(SteamToken token, string steamId, bool autoUpdate = false, LoadType loadType = LoadType.OnRequest)
            : base(token, steamId)
        {
            Ini(loadType);
            if (autoUpdate)
            {
                token.MessageReceived += _notification_MessageReceived;
            }
        }

        private void Ini(LoadType loadType)
        {
            _loadType = loadType;
            switch (loadType)
            {
                case LoadType.All:
                    _user = Core.GetUserInfo(SteamId);
                    _iGroups = _groups.Select(x => new iGroup(Token, x.SteamId)).ToList();
                    _iUsers = _friends.Select(x => new iUser(Token, x.SteamId)).ToList();
                    break;
                case LoadType.DataOnly:
                    _user = Core.GetUserInfo(SteamId);
                    break;
            }
        }
        
        void _notification_MessageReceived(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            if (e == null) return;
            var args = (NotificationCompletedEventArgs)e;

            switch (args.Poll.Message)
            {
                case "Timeout":
                    Refresh(RefreshType.Data);
                    Refresh(RefreshType.UserList);
                    OnUpdatedEvent(new OnUpdatedEventArgs());
                    break;
                case "Not Loggen On":
                    Token.Authenticate(Token.AccessToken);
                    Refresh(RefreshType.Data);
                    Refresh(RefreshType.UserList);
                    OnUpdatedEvent(new OnUpdatedEventArgs());
                    break;
                default:
                    if (args.Poll.UpdateMessages == null || args.Poll.UpdateMessages.Count == 0) return;
                    foreach (var message in args.Poll.UpdateMessages)
                    {
                        switch (message.MessageType)
                        {
                            case UpdateType.UserUpdate:
                                {
                                    var curStatus = (UserStatus) Convert.ToInt32(message.Status);
                                    if (_user.SteamId == message.Origin && _user.Status != curStatus)
                                    {
                                        _user.Status = curStatus;
                                        OnUpdatedEvent(new OnUpdatedEventArgs(message));
                                    }
                                    else
                                    {
                                        foreach (var user in Friends.Where(user => user.SteamId == message.Origin && user.Data.Status != curStatus))
                                        {
                                            user.Data.Status = curStatus;
                                            OnUpdatedEvent(new OnUpdatedEventArgs(message));
                                        }
                                    }
                                }
                                break;
                            case UpdateType.Message:
                                {
                                    OnMessageReceivedEvent(new OnMessageReceivedEventArgs(message));
                                    break;
                                }
                        }
                    }
                    break;
            }
        }

        public void SendMessage(string message)
        {
            Core.SendMessage(_user, message);
        }
        public void SendMessage(string message, string steamId)
        {
            Core.SendMessage(steamId, message);
        }
        public void SendMessage(string message, User user)
        {
            Core.SendMessage(user, message);
        }

        public void SendTypingNotification()
        {
            Core.SendTypingNotification(_user);
        }
        public void SendTypingNotification(string steamId)
        {
            Core.SendTypingNotification(Core.GetUserInfo(steamId));
        }
        public void SendTypingNotification(User user)
        {
            Core.SendTypingNotification(user);
        }

        public void Refresh(RefreshType refreshType)
        {
            switch (refreshType)
            {
                case RefreshType.All:
                    _user = _loadType == LoadType.OnRequest ? null : Core.GetUserInfo(SteamId);
                    _iGroups = _loadType == LoadType.OnRequest ? null : _groups.Select(x => new iGroup(Token, x.SteamId)).ToList();
                    _iUsers = _loadType == LoadType.OnRequest ? null : _friends.Select(x => new iUser(Token, x.SteamId)).ToList();
                    break;
                case RefreshType.Data:
                    _user = _loadType == LoadType.OnRequest ? null : Core.GetUserInfo(SteamId);
                    break;
                case RefreshType.UserList:
                    _iUsers = _loadType == LoadType.OnRequest ? null : _friends.Select(x => new iUser(Token, x.SteamId)).ToList();
                    break;
                case RefreshType.GroupList:
                    _iGroups = _loadType == LoadType.OnRequest ? null : _groups.Select(x => new iGroup(Token, x.SteamId)).ToList();
                    break;
            }
        }

        public Bitmap Avatar(AvatarSize size)
        {
            return Core.GetUserAvatar(_user, size);
        }

        #region Properties

        public User Data
        {
            get
            {
                if (_user == null)
                    _user = Core.GetUserInfo(SteamId);
                return _user;
            }
        }
        public List<iGroup> Groups
        {
            get
            {
                if (_iGroups == null)
                {
                    _groups = Core.GetGroups(SteamId);
                    _iGroups = _groups.Select(x => new iGroup(Token, x.SteamId)).ToList();
                }
                return _iGroups;
            }
        }
        public List<iUser> Friends
        {
            get
            {
                if (_iUsers == null)
                {
                    _friends = Core.GetFriends(SteamId);
                    _iUsers = _friends.Select(x => new iUser(Token, x.SteamId)).ToList();
                }
                return _iUsers;
            }
        }

        public LoadType LoadType
        {
            get { return _loadType; }
            set { _loadType = value; }
        }

        #endregion
    }

    public class BaseEventArgs : EventArgs
    {
        private readonly Update _message;

        public BaseEventArgs(Update message)
            : base()
        {
            _message = message;
        }

        public BaseEventArgs()
            : base()
        {

        }

        public Update Message
        {
            get { return _message; }
        }
    }

    public class OnUpdatedEventArgs : BaseEventArgs
    {
        public OnUpdatedEventArgs(Update message) : base (message)
        {
        }

        public OnUpdatedEventArgs()
            : base()
        {
        }
    }

    public class OnMessageReceivedEventArgs : BaseEventArgs
    {
        public OnMessageReceivedEventArgs(Update message) : base (message)
        {
        }

        public OnMessageReceivedEventArgs()
            : base()
        {
        }
    }
}